package com.example.test06thread.volatileTest;

/**
 * @Author: fxy
 * @Date: 2023/01/04/14:14
 * @Description: https://blog.csdn.net/weixin_30342639/article/details/91356608
 */
public class VolatileTest {
    public static void main(String[] args) {

        for(int i=0;i<100;i++){
            new Thread(()->{
                Singleton singleton = Singleton.getInstance();
                System.out.println(System.identityHashCode(singleton));
            }).start();
        }
    }
}
class Singleton {

    /*
    * 由上可以看到，instance变量被volatile关键字所修饰，但是如果去掉该关键字，就不能保证该代码执行的正确性。这是因为“instance = new Singleton();”这行代码并不是原子操作，其在JVM中被分为如下三个阶段执行：
                为instance分配内存
                初始化instance
                将instance变量指向分配的内存空间
    由于JVM可能存在重排序，上述的二三步骤没有依赖的关系，可能会出现先执行第三步，后执行第二步的情况。也就是说可能会出现instance变量还没初始化完成，其他线程就已经判断了该变量值不为null，结果返回了一个没有初始化完成的半成品的情况。
    * 而加上volatile关键字修饰后，可以保证instance变量的操作不会被JVM所重排序，每个线程都是按照上述一二三的步骤顺序的执行，这样就不会出现问题。

* */
    private volatile static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}